import { _decorator, Component } from 'cc';
import { DEFAULT_MAGAZINE_LOW_THRESHOLD, TICK_RATES } from '../shared';
import { GlobalEventBus } from '../core/EventBus';
import { getWeaponStats } from '../data/WeaponRepository';
import type { WeaponStats } from '../shared';
import { track } from '../telemetry/Track';
import WeaponController from '../gameplay/WeaponController';
import { Clock } from '../core/Clock';

const { ccclass, property } = _decorator;

type WeaponSlot = 'primary' | 'secondary';

@ccclass('AutoReloadSystem')
export class AutoReloadSystem extends Component {
  @property
  public lowAmmoThreshold = DEFAULT_MAGAZINE_LOW_THRESHOLD;

  private activeSlot: WeaponSlot = 'primary';
  private reloading = false;
  private ceaseFire = false;
  private speedNorm = 0;
  private weaponController: WeaponController | null = null;
  private unsubscribeAmmoOut: (() => void) | null = null;
  private unsubscribeAmmoChanged: (() => void) | null = null;
  private clockRef: Clock | null = null;
  private pollKey: string = '';

  onLoad() {
    this.weaponController = this.node.getComponent(WeaponController) ?? null;
  }

  onEnable() {
    // Ensure WC cached when enabled (in case of attach order)
    this.weaponController = this.node.getComponent(WeaponController) ?? this.weaponController;
    this.reloading = false;
    // Event trigger: ammo out
    this.unsubscribeAmmoOut = GlobalEventBus.on('ammo/out', () => this.onOut());
    // Fallback polling via Clock: every 0.1s (10 Hz)
    this.clockRef = this.node.getComponent(Clock) ?? null;
    this.pollKey = `reload-check-${this.node.uuid}`;
    if (this.clockRef) {
      // Ensure no double registration
      (this.clockRef as any).unregister?.(this.pollKey);
      this.clockRef.register(this.pollKey, TICK_RATES.navigation, () => {
        const wc = this.weaponController;
        if (!wc) return;
        if (!this.reloading && wc.canReload()) {
          this.beginReload();
        } else if (!this.reloading && !wc.canReload()) {
          this.trySwitchOrToast();
        }
      });
    }
    // Any ammo change could clear cease fire
    this.unsubscribeAmmoChanged = GlobalEventBus.on('ammo/changed', () => { this.ceaseFire = false; });
  }

  update(_dt: number) {}

  public getActiveWeaponStats(): WeaponStats | undefined {
    if (this.weaponController) {
      return getWeaponStats(this.weaponController.getActiveWeaponId());
    }
    return undefined;
  }

  public getActiveWeaponId(): string {
    if (this.weaponController) {
      return this.weaponController.getActiveWeaponId();
    }
    return '';
  }

  // AutoReloadSystem no longer manages internal ammo supply; WeaponController is SSOT

  public setSpeedNorm(norm: number) {
    this.speedNorm = norm;
  }

  public getSpeedNorm(): number {
    return this.speedNorm;
  }

  public isReloading(): boolean {
    return this.reloading;
  }

  public isCeaseFire(): boolean {
    return this.ceaseFire;
  }

  private onOut() {
    if (this.reloading) {
      if (typeof console !== 'undefined' && console.debug) {
        console.debug('[RELOAD] ignore out (reloading)');
      }
      return;
    }
    const wc = this.weaponController;
    if (!wc) return;
    if (wc.canReload()) {
      this.beginReload();
    } else {
      this.trySwitchOrToast();
    }
  }

  private handleEmptyMagazineWC() {
    if (!this.weaponController) return;
    const cur = this.weaponController.getCurrent();
    const payload = { weaponId: cur.id };
    GlobalEventBus.emit('ammo/out', payload);
    track('ammo_out', payload);
    if (typeof console !== 'undefined' && console.debug) {
      console.debug('[RELOAD] ammo/out', payload);
    }
    if (cur.reserve > 0) {
      this.beginReloadWC();
      return;
    }
    // Try switch to secondary when primary is empty and no reserve
    const before = this.weaponController.getActiveSlot();
    const switched = this.weaponController.trySwitchSecondary();
    const after = this.weaponController.getActiveSlot();
    if (switched && after !== before) {
      if (typeof console !== 'undefined' && console.debug) {
        console.debug('[WEAPON] switch->secondary');
      }
      GlobalEventBus.emit('hud/toast', { text: '已切换副武器', ms: 600 });
      this.ceaseFire = false;
      // If switched weapon also empty but has reserve, start reload for it
      const next = this.weaponController.getCurrent();
      if (next.mag === 0 && next.reserve > 0) {
        this.beginReloadWC();
      }
      return;
    }
    this.ceaseFire = true;
    GlobalEventBus.emit('hud/toast', { text: '弹药告急', ms: 1500 });
    if (typeof console !== 'undefined' && console.debug) {
      console.debug('[RELOAD] cease fire: out of ammo');
    }
  }

  private beginReload() {
    const wc = this.weaponController;
    if (!wc || this.reloading) return;
    if (!wc.canReload()) return;
    this.reloading = true;
    const cur = wc.getCurrent();
    const t = cur.reloadSec;
    GlobalEventBus.emit('reload/begin', { weaponId: cur.id, t });
    if (typeof console !== 'undefined' && console.debug) {
      console.debug('[RELOAD] begin t=', t);
    }
    // Use Cocos scheduler to simulate reload time
    this.scheduleOnce(() => {
      wc.reloadOnce();
      this.reloading = false;
      const after = wc.getCurrent();
      GlobalEventBus.emit('reload/end', { weaponId: after.id });
      if (typeof console !== 'undefined' && console.debug) {
        console.debug('[RELOAD] end mag/reserve', after.mag, after.reserve);
      }
    }, Math.max(0, t));
  }

  private trySwitchOrToast() {
    const wc = this.weaponController;
    if (!wc) return;
    const cur = wc.getCurrent();
    if (cur.mag === 0 && cur.reserve === 0) {
      const switched = wc.trySwitchSecondary();
      if (switched) {
        if (typeof console !== 'undefined' && console.debug) {
          console.debug('[WEAPON] switch->secondary');
        }
        GlobalEventBus.emit('hud/toast', { text: '已切副武器', ms: 1200 });
      } else {
        GlobalEventBus.emit('hud/toast', { text: '弹药告急', ms: 1500 });
        this.ceaseFire = true;
      }
    }
  }

  onDisable() {
    this.unsubscribeAmmoOut?.();
    this.unsubscribeAmmoOut = null;
    this.unsubscribeAmmoChanged?.();
    this.unsubscribeAmmoChanged = null;
    if (this.clockRef && this.pollKey) {
      this.clockRef.unregister(this.pollKey);
    }
    this.clockRef = null;
    this.unscheduleAllCallbacks();
  }

}

